package persistencia.dao;


import java.lang.reflect.Method;

import java.util.List;

import org.hibernate.criterion.DetachedCriteria;

import org.springframework.orm.hibernate3.HibernateTemplate;

import persistencia.session.HibernateSession;
import persistencia.session.Factory;


public class GenericoDAO {

    private HibernateTemplate hibernateTemplate;

    public GenericoDAO() {
        // Genera la configuracion de hibernate.
        Factory factoria = Factory.getInstance();

        // Obtenemos la fachada que nos ofrece Spring para trabajar con Hibernate.
        this.hibernateTemplate = 
                ((HibernateSession)factoria.getBean("session")).getHibernateTemplate();
    }

    /**
     * Pesiste un objeto en la base de datos.
     * @param obj Objeto a persistir.
     */
    public void persistir(Object obj) {
        this.hibernateTemplate.persist(obj);
    }

    /**
     * Elimina un objeto de la base de datos.
     * @param obj Objeto a eliminar.
     */
    public void eliminar(Object obj) {
        this.hibernateTemplate.delete(obj);
    }

    public void modificar(Object obj){
        this.hibernateTemplate.update(obj);
    }

    /**
     * Obtiene el metodo modificador correspondiente a cierto metodo consultor
     * con los parametro descritos
     * 
     * @param metodoConsultor
     * @param clase
     * @param parametro
     * @return el metodo modificador correspondiente a cierto metodo consultor
     */
    @SuppressWarnings("unchecked")
    private Method obtenerMetodoModificador(String metodoConsultor, 
                                            Class clase, 
                                            Class parametro) throws NoSuchMethodException {

        String nombreMetodoModificador = "set" + metodoConsultor.substring(3);
        Class[] parametros = { parametro };

        Method metodo = clase.getMethod(nombreMetodoModificador, parametros);

        return metodo;
    }

    /**
     * Obtiene todos los elementos de una clase persistente almacenada en la base de datos.
     * @param <T>
     * @param clasePersistente Clase del objeto persistente.
     * @return
     */
    @SuppressWarnings("unchecked")
    public <T> List<T> obtenerTodos(final Class clasePersistente) {

        return this.hibernateTemplate.findByCriteria(DetachedCriteria.forClass(clasePersistente));
    }


    /**
     * Metodo para realizar una busqueda por identificador.
     * @param <T>
     * @param clasePersistente
     * @param id
     * @return
     */
    @SuppressWarnings("unchecked")
    public <T> T buscarPorId(final Class clasePersistente, final Long id) {

        DetachedCriteria criterio = 
            Criterios.crearCriterioVacio(clasePersistente);
        Criterios.addRestricctionId(criterio, id);

        Object result = null;
        List objetosPersistentes = 
            this.hibernateTemplate.findByCriteria(criterio);
        if (!objetosPersistentes.isEmpty())
            result = objetosPersistentes.get(0);

        return (T)result;
    }


    /**
     * 
     * @param criterio
     * @return
     */
    public <T> List<T> buscarPorCriterio(DetachedCriteria criterio) {
        return this.hibernateTemplate.findByCriteria(criterio);
    }

    /**
     * @param criterio
     * @param n
     * @return
     */
    public <T> List<T> buscarNPorCriterio(DetachedCriteria criterio, int n) {
        return this.hibernateTemplate.findByCriteria(criterio,0,n);
    }
}
